import io
import socket
import os
import json
import threading

CHUNK_SIZE=2048*1024#1Mb
TRACKER_IP='192.168.56.106'
PORT=6666
SOCKET_BUFFER_SIZE=1024
LOCAL_IP='192.168.56.104'
MEDIA_TYPE='.mp4'

infos=[]#a list that contains each file status
peer_ip_list=set()

def init():
    files=os.listdir()
    for file in files:
        if MEDIA_TYPE in file:
            size=os.path.getsize(file)
            info={'path':file,'size':size}
            global infos
            infos.append(info)

def send_to_tracker():
    file_list=os.listdir()
    file_info=[]
    for file in file_list:
        if MEDIA_TYPE in file:
            size=os.path.getsize(file)
            file_info.append({'file_name':file,'file_size':size})
    register={'request_type':1,'file_list':file_info}
    register=json.dumps(register).encode()
    sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
    sock.connect((TRACKER_IP,PORT))
    print('Send files information to the server...')

    for i in range(len(register)//SOCKET_BUFFER_SIZE+1):
        start=i*SOCKET_BUFFER_SIZE
        end=min(len(register),start+SOCKET_BUFFER_SIZE-1)
        sock.send(register[start:end])

    recv=sock.recv(SOCKET_BUFFER_SIZE)
    recv=json.loads(recv.decode())
    print(recv['status_code'])
    sock.close()

class fileTransfer(threading.Thread):
    def __init__(self,conn,path,start_chunk,end_chunk):
        threading.Thread.__init__(self)
        self.conn=conn
        self.path=path
        self.start_chunk=start_chunk
        self.end_chunk=end_chunk

    def run(self):
        file=open(self.path,'rb')
        # recv=self.conn.recv(SOCKET_BUFFER_SIZE)
        # recv=json.loads(recv.decode())
        # print(recv)
        # start_chunk=recv['start_chunk']
        # end_chunk=recv['end_chunk']
        start_size=self.start_chunk*CHUNK_SIZE
        file.seek(start_size,io.SEEK_SET)
        end_size=min(os.path.getsize(self.path)-1,(1+self.end_chunk)*CHUNK_SIZE-1)
        print(start_size,end_size)
        while start_size<end_size:
            data=file.read(SOCKET_BUFFER_SIZE)
            start_size+=len(data)
            # print(start_size)
            self.conn.send(data)
        self.conn.send(b'')
        self.conn.close()
        file.close()


class myDaemon(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
            sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            sock.bind((LOCAL_IP,PORT))
            sock.listen()

            while True:
                conn,addr=sock.accept()
                request=conn.recv(SOCKET_BUFFER_SIZE)
                request=json.loads(request.decode())

                global peer_ip_list
                if not addr[0]==TRACKER_IP:
                    peer_ip_list.add(addr[0])

                if addr[0]==TRACKER_IP and not request['source']==LOCAL_IP:
                    print('Group conversation')
                    print('\nMessage from {}:\n{}\n'.format(request['source'],request['message']))
                    conn.close()
                    continue

                if request['request_type']==2:
                    print('Private conversation')
                    print('\nMessage from {}:\n{}\n'.format(addr[0],request['message']))
                    conn.close()
                    continue

                request_file=request['file_name']
                print('Message from',addr[0],':',request)
                # if not request['start_chunk']==-1:
                #     continue

                # pos=-1
                # for i in range(len(infos)):
                #     if infos[i]['path']==request_file:
                #         pos=i
                #         break
                # if pos<0:
                #     response={'status_code':404}
                #     response=json.dumps(response).encode()
                #     conn.send(response)
                #     conn.close()
                # else:
                #     response={'status_code':200,'info':infos[pos]}
                #     response=json.dumps(response).encode()
                #     conn.send(response)
                #     ft=fileTransfer(conn,request_file)
                #     ft.start()
                start_chunk=request['start_chunk']
                end_chunk=request['end_chunk']
                fileTransfer(conn,request_file,start_chunk,end_chunk).start()
            sock.close()

class wait_input(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)

    def run(self):
        while True:
            message=input('please input here:\n')
            sock=socket.socket(socket.AF_INET,socket.SOCK_STREAM)
            print('Send to...:\n')
            
            peer_num=len(peer_ip_list)
            peer_list=list(peer_ip_list)
            for i in range(peer_num):
                print('{}. {}'.format(i,peer_list[i]))
            print('{}. all peers'.format(peer_num))
            op=int(input())

            if op==peer_num:
                sock.connect((TRACKER_IP,PORT))
            else:
                sock.connect((peer_list[op],PORT))
            request={'request_type':2,'message':message}
            request=json.dumps(request).encode()
            sock.send(request)
            sock.close()


init()
send_to_tracker()
daemon=myDaemon()
daemon.start()
wait_input().start()
